package org.colcon.web.model.parsers;

import java.util.HashMap;
import java.util.Map;

import org.colcon.web.model.Agent;
import org.colcon.web.model.Ballot;
import org.colcon.web.model.ColCon;
import org.colcon.web.model.Command;
import org.colcon.web.model.Container;
import org.colcon.web.model.Group;
import org.colcon.web.model.Item;
import org.colcon.web.model.Law;
import org.colcon.web.model.Link;
import org.colcon.web.model.LinkContainer;
import org.colcon.web.model.News;
import org.colcon.web.model.Title;
import org.colcon.web.model.User;
import org.colcon.web.model.framework.IItem;
import org.colcon.web.model.vote.ConfirmationVote;
import org.colcon.web.model.vote.NominationVote;
import org.colcon.web.model.vote.SelectionVote;
import org.colcon.web.server.Model;

public class CLIParser 
{
	public static final String
	
		DELIMETER = " ",
		ARG_TAG = "-",

		// command arguments
		CMD = "cmd",
		PATH = "path",
		TEXT = "text",
		ITEM = "item",
		TYPE = "type",
		NEXT = "next",
		ARG = "arg",
		LONG = "long";
	
	public static Map<String, String> parse(String str)
	{
		if(str == null)
			return null;
		
		Map<String, String> args = new HashMap<String, String>();
		
		if(str.length() == 0)
			return args;
		
		str += " ";
		
		String key = "";
		String value = "";
		int nested = 0;
		boolean parsingKey = true;
		
		for(int i = 0; i < str.length(); i++)
		{
			char c = str.charAt(i);
			
			if(c == '{')
			{
				nested++;
				
				if(nested == 1)
					continue;
			}
			else if(c == '}')
			{
				nested--;
				
				if(nested == 0)
					continue;
			}
			
			if(nested == 0)
			{
				if(c == ' ')
				{
					if(parsingKey)
						parsingKey = false;
					else if(key.trim().length() > 0)
					{
						key = key.trim();
						value = value.trim();
						
						if(args.containsKey(key))
							args.put(key, args.get(key) + " ; " + value);
						else
							args.put(key, value);
						
						key = "";
						value = "";
					}
				}
				else if(c == '-' && i+1 < str.length() && !Character.isDigit(str.charAt(i+1)))
				{
					key = "";
					parsingKey = true;
				}
				else
				{
					if(parsingKey)
						key += c;
					else
						value += c;
				}
			}
			else
			{
				value += c;
			}
		}
			
		return args;
	}
	
	public static Map<String, String> parseCommand(String command)
	{
		Map<String, String> args = new HashMap<String, String>();

		String[] array = command.split(" ");
		
		if(array == null || array.length == 0)
			return args;
		
		String cmdArgs = "";
		
		for(int i = 0; i < array.length; i++)
			cmdArgs += array[i] + " ";
		
		args = parse(cmdArgs);
		
		args.put(CMD, parseCmd(command));
		args.put(PATH, parsePath(command));
		
		return args;
	}
	
	public static String parseCmd(String command)
	{
		if(command == null)
			return null;
		
		String[] array = command.split(" ");
		
		if(array == null || array.length == 0)
			return null;
		
		String str;
		
		if(array[0].equals("-cmd") && array.length > 1)
			str = array[1];
		else
			str = array[0];
		
		if(str == null || str.trim().length() == 0)
			return null;
		
		String[] cmd = str.split("/");
		
		if(cmd.length == 1)
			return "colcon/commands/" + str;
		else if(!cmd[0].equals(Model.ROOT))
			return Model.ROOT + '/' + str;
		else
			return str;
	}
	
	public static String parsePath(String command)
	{
		if(command == null)
			return null;
		
		String[] array = command.split(" ");
		
		if(array == null || array.length < 1)
			return null;
		
		String str;
		
		if(!array[0].equals("-cmd") && array.length > 1 && !array[1].startsWith("-"))
			str = array[1];
		else if(parse(command).containsKey(PATH))
			str = parse(command).get(PATH);
		else
			return null;
		
		String[] path = str.split("/");
		
		if(!path[0].equals(Model.ROOT))
			return Model.ROOT + '/' + str;
		else
			return str;
	}
	
	public static IItem parseItem(String item)
	{
		return parseItem(parse(item));
	}
	
	public static IItem parseItem(Map<String, String> args)
	{
		//TODO: validate args
		
		String type = args.get(TYPE);
		
		if(type == null)
			return null;
		
		//TODO: replace string literals with class names
		
		if(type.equals("colcon")) 					return new ColCon(args);
		else if(type.equals("item")) 				return new Item(args);
		else if(type.equals("container")) 			return new Container(args);
		else if(type.equals("link")) 				return new Link(args);
		else if(type.equals("link_container")) 		return new LinkContainer(args);
		else if(type.equals("agent")) 				return new Agent(args);
		else if(type.equals("user")) 				return new User(args);
		else if(type.equals("group"))				return new Group(args);
		else if(type.equals("law")) 				return new Law(args);
		else if(type.equals("title"))				return new Title(args);
		else if(type.equals("confirmation_vote"))	return new ConfirmationVote(args);
		else if(type.equals("selection_vote"))		return new SelectionVote(args);
		else if(type.equals("nomination_vote"))		return new NominationVote(args);
		else if(type.equals("ballot"))				return new Ballot(args);
		else if(type.equals("command"))				return new Command(args);
		else if(type.equals("news"))				return new News(args);
		//TODO: add missing classes
		
		return null;
	}
	
}
